﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Threading.Tasks.Schedulers;
using System.Windows.Forms;
using TextToVoice;

/// <summary>
/// 1、需要改成多线程
/// 2、progressbar过程中显示文件名称等
/// 3、用户配置文件保存用户配置，记录之前选择
/// </summary>
namespace txt_to_voice
{
    public partial class MainForm : Form
    {
        public static string API_KEY = TextToVoice.Properties.Settings.Default.API_KEY;
        public static string SECRET_KEY = TextToVoice.Properties.Settings.Default.SECRET_KEY;
        public static string AppId = TextToVoice.Properties.Settings.Default.AppId;

        public static string savePath = "";
        private string filePath = "";
        

        List<InnerChapter> chaptersList = new List<InnerChapter>();      //文件按章节拆分后的List集合


        public MainForm()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            FolderBrowserDialog folderBrowserDialog = new FolderBrowserDialog();
            if (folderBrowserDialog.ShowDialog() == DialogResult.OK)
            {
                savePath = folderBrowserDialog.SelectedPath;
            }

        }

        private void Form1_Load(object sender, EventArgs e)
        {
            string API_KEY = TextToVoice.Properties.Settings.Default.API_KEY;
            string SECRET_KEY = TextToVoice.Properties.Settings.Default.SECRET_KEY;

            this.num_speed.Value = TextToVoice.Properties.Settings.Default.usr_speed;
            this.num_voice.Value = TextToVoice.Properties.Settings.Default.usr_voice;
            this.num_pit.Value = TextToVoice.Properties.Settings.Default.usr_pit;

            Dictionary<int, string> cmOption = new Dictionary<int, string>();
            cmOption.Add(0, "女声");
            cmOption.Add(1, "男声");
            cmOption.Add(3, "度逍遥");
            cmOption.Add(4, "度丫丫");
            this.cm_per.DataSource = new BindingSource(cmOption, null);
            this.cm_per.ValueMember = "Key";
            this.cm_per.DisplayMember = "Value";
            this.cm_per.SelectedIndex = 2;
        }


        private void button2_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(filePath) || string.IsNullOrEmpty(savePath))
            {
                MessageBox.Show("请先选择文件保存路径和文本文件");
            }
            else
            {
                if (this.chaptersList.Count <= 0)
                {
                    MessageBox.Show("请至少选中一条需要转换的文本");
                    return;
                }
                this.panel1.BeginInvoke(new Action(() => { this.panel1.Controls.Clear(); }));   //清空上次转换后自动生成的进度条
                this.doFilter();        //将待转换chapterList更新为预览中复选框选中的章节。

                int maxTask = Convert.ToInt32( this.thread_quantity.Value);

                this.button1.Enabled = false;
                this.button2.Enabled = false;
                this.btn_save_path.Enabled = false;
                this.preview.Enabled = false;

                var option = new Dictionary<string, object>()
                    {
                        {"spd", num_speed.Value},
                        {"vol", num_voice.Value},
                        {"per", cm_per.SelectedValue}
                    };

             
                TaskFactory fac = new TaskFactory(new LimitedConcurrencyLevelTaskScheduler(maxTask));
                fac.StartNew(() =>
                {
                    FileInfo fileInfo = new FileInfo(filePath);
                    string filename = fileInfo.Name.Replace(fileInfo.Extension, "");

                    //进行文本语音合成
                    this.convert_progress_all.BeginInvoke(new Action<int>((x) => { this.convert_progress_all.Maximum = x; this.convert_progress_all.Value = 0; }), this.chaptersList.Count);
                    List<Task> taskList = new List<Task>();
                    foreach (InnerChapter chapter in this.chaptersList)     //每一个线程完成一个章节的转换及文件写入
                    {
                        Task t = Task.Factory.StartNew(() =>
                       {
                           List<string> stringList = this.GetStringList(chapter.content.ToString(), 500, '。');
                           ProgressBar progressBar = this.addProgressBar();
                           while (true)
                           {
                               if (progressBar.IsHandleCreated)
                               {
                                   progressBar.BeginInvoke(new Action<int>((x) => { progressBar.Maximum = x; }), stringList.Count);
                                   break;
                               }
                           }
                           List<byte> voiceByteList = new List<byte>();
                           foreach (var tmpText in stringList)
                           {
                               var voiceData = this.getVoiceData(tmpText, option);
                               if (voiceData != null)
                               {
                                   voiceByteList.AddRange(voiceData);
                                   Console.WriteLine("完成一次声音请求");
                                   progressBar.BeginInvoke(new Action(() => { progressBar.Value++; }));
                               }
                           }
                           this.convert_progress_all.BeginInvoke(new Action(() => { this.convert_progress_all.Value++; }));
                           File.WriteAllBytes(MainForm.savePath + "\\" + filename + chapter.title+".mp3", voiceByteList.ToArray());
                       });
                        taskList.Add(t);
                        Console.WriteLine("task的id为" + t.Id);
                    }
                    Task.WaitAll(taskList.ToArray());
                    //回复按钮状态及进度条清空
                    this.button1.BeginInvoke(new Action(()=> { this.button1.Enabled = true; }));
                    this.button2.BeginInvoke(new Action(() => { this.button2.Enabled = true; }));
                    this.btn_save_path.BeginInvoke(new Action(() => { this.btn_save_path.Enabled = true; }));
                    this.preview.BeginInvoke(new Action(() => { this.preview.Enabled = true; }));
                 
                    MessageBox.Show("转换完成");
                });
            }
        }




        private void button1_Click_1(object sender, EventArgs e)
        {
            OpenFileDialog openFileDialog = new OpenFileDialog();
            openFileDialog.InitialDirectory = "c:\\";//注意这里写路径时要用c:\\而不是c:\
            openFileDialog.Filter = "文本文件|*.*|所有文件|*.*";
            openFileDialog.RestoreDirectory = true;
            openFileDialog.FilterIndex = 1;
            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                filePath = openFileDialog.FileName;
            }
        }



        #region  txt-to-voice相关



        /// <summary>
        /// 文本转语音文件
        /// </summary>
        /// <param name="text"></param>
        /// <returns></returns>
        private byte[] getVoiceData(string text, Dictionary<string, object> option)
        {
            var client = new Baidu.Aip.Speech.Tts(MainForm.API_KEY, MainForm.SECRET_KEY);
            client.Timeout = 60000;  // 修改超时时间
            client.AppId = MainForm.AppId;
            int times = 0;
            try
            {
                var result = client.Synthesis(text, option);
                if (result.ErrorCode == 0)
                {
                    return result.Data;
                }
                else
                {
                    return null;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
                if (times < 3)
                {
                    times++;
                    var result = client.Synthesis(text, option);
                    if (result.ErrorCode == 0)
                    {
                        return result.Data;
                    }
                    else
                    {
                        return null;
                    }
                }
                else
                {
                    return null;
                }
            }
            
        }

        /// <summary>
        /// 由于api接口单次请求有文本字符长度的限制，因此按照指定长度进行拆分。（优化：100个字符以内若出现句号，则以句号作为拆分标示，避免语音还原拼凑在一起时生硬停顿）
        /// </summary>
        /// <param name="text"></param>
        /// <param name="length"></param>
        /// <returns></returns>
        private List<string> GetStringList(string content, int length, char sign)
        {
            List<string> resultList = new List<string>();
            //按句号分割成List
            var resultTmp = content.Split(sign).ToList();
            //对句号分割后的List进行长度修正
            foreach (var item in resultTmp)
            {
                int startIndex = 0;
                if (item.Length > length)
                {
                    do
                    {
                        string resultItem;
                        if (item.Length - startIndex >= length)
                            resultItem = item.Substring(startIndex, length);
                        else
                            resultItem = item.Substring(startIndex);
                        resultList.Add(resultItem);
                        startIndex += length;
                    } while (startIndex < item.Length);
                }
                else
                {
                    resultList.Add(item);
                }
            }
            return resultList;
        }

       


        #endregion

        int progressCount = 0;

        private ProgressBar addProgressBar()
        {
            ProgressBar progressBar = new ProgressBar();
            progressBar.Width = this.panel1.Width - 100;
            progressBar.Height = 20;
            progressBar.BringToFront();
            progressBar.Location = new Point(5, progressCount * 20 + 5);
            this.panel1.BeginInvoke(new Action(() => { this.panel1.Controls.Add(progressBar); }));
            progressCount++;
            //this.panel1.BeginInvoke(new Action(()=> { this.panel1.Refresh(); }));
            Console.WriteLine("增加了一个progressbar");
            return progressBar;
        }

        private void preview_Click(object sender, EventArgs e)
        {
            ChapterCut chapterCut = new ChapterCut();
            if (string.IsNullOrEmpty(filePath))
            {
                MessageBox.Show("请先选择文件");
            }
            else
            {
                this.chaptersList =   chapterCut.getChapters(this.txt_regStr.Text.Trim(),this.txt_reg_symbol.Text.Trim(), filePath);

                this.listView1.Columns.Add("", 20);
                this.listView1.Columns.Add("章节标题", 100);
                this.listView1.Columns.Add("章节编号", 40);
                this.listView1.Columns.Add("章节内容", 300);
                this.listView1.BeginUpdate();
                foreach (InnerChapter innerChapter in chaptersList)
                {
                    ListViewItem lvi = new ListViewItem();
                    lvi.Checked = true;         //默认全部选中
                    lvi.SubItems.Add(new ListViewItem.ListViewSubItem(lvi, innerChapter.title));
                    lvi.SubItems.Add(new ListViewItem.ListViewSubItem(lvi, innerChapter.no.ToString()));
                    lvi.SubItems.Add(new ListViewItem.ListViewSubItem(lvi, innerChapter.content.ToString().Substring(0, 3)));
                    this.listView1.Items.Add(lvi);
                }
                this.listView1.EndUpdate();

                if (this.chaptersList.Count > 0)
                {
                    this.num_section_start.Value = 1;
                    this.num_section_end.Value = this.chaptersList.Count;
                }
            }
        }


        private void doFilter()
        {
            //this.chaptersList.Clear();
            List<InnerChapter> newChapters = new List<InnerChapter>();
            foreach (ListViewItem tmpItem in this.listView1.Items)
            {
                if (tmpItem.Checked)
                {
                    newChapters.Add(this.chaptersList[Convert.ToInt32(tmpItem.SubItems[2].Text)-1]);
                }
            }
            this.chaptersList = newChapters;
        }

        private void btn_checkedall_Click(object sender, EventArgs e)
        {
            foreach (ListViewItem tmpItem in this.listView1.Items)
            {
                tmpItem.Checked = true;
            }
        }

        private void btn_cancelall_Click(object sender, EventArgs e)
        {
            foreach (ListViewItem tmpItem in this.listView1.Items)
            {
                tmpItem.Checked = false;
            }
        }

        private void 关于ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            AboutForm aboutForm = new AboutForm();
            aboutForm.Show();
        }

        private void btn_save_settings_Click(object sender, EventArgs e)
        {
            TextToVoice.Properties.Settings.Default.usr_pit = Convert.ToInt32(this.num_pit.Value);
            TextToVoice.Properties.Settings.Default.usr_speed = Convert.ToInt32(this.num_speed.Value);
            TextToVoice.Properties.Settings.Default.usr_voice = Convert.ToInt32(this.num_voice.Value);
            TextToVoice.Properties.Settings.Default.Save();
            MessageBox.Show("保存配置完成");
        }

        private void btn_section_Click(object sender, EventArgs e)
        {
            int startIndex =Convert.ToInt32( this.num_section_start.Value);
            int endIndex = Convert.ToInt32(this.num_section_end.Value);
            foreach (ListViewItem tmpItem in this.listView1.Items)
            {
                if (Convert.ToInt32(tmpItem.SubItems[2].Text) >= startIndex && Convert.ToInt32(tmpItem.SubItems[2].Text) <= endIndex)
                {
                    tmpItem.Checked = true;
                }
            }
        }
    }
}
